// 生成手上胡牌组合，最多14张； 万,筒,条以0间隔
#include <cstring>
#include <set>
#include <fstream>
using namespace std;
const int BLOCK_SIZE = 76;
const int BLOCK_ABC_START = 1;
const int BLOCK_ABC_COUNT = 21;
const int BLOCK_TTT_START = 22;
const int BLOCK_TTT_COUNT = 27;
const int BLOCK_PPZ_START = 49;
const int BLOCK_PPZ_COUNT = 27;
// 编码(万)：0x01~0x09 
// 编码(筒)：0x11~0x19 
// 编码(条)：0x21~0x29 

// 有效的
char TileBlock[BLOCK_SIZE][3] = {
	{ 0x00,0x00,0x00 }, //无效占位
	// 顺子
	{0x01,0x02,0x03},
	{0x02,0x03,0x04},
	{0x03,0x04,0x05},
	{0x04,0x05,0x06},
	{0x05,0x06,0x07},
	{0x06,0x07,0x08},
	{0x07,0x08,0x09},

	{0x11,0x12,0x13},
	{0x12,0x13,0x14},
	{0x13,0x14,0x15},
	{0x14,0x15,0x16},
	{0x15,0x16,0x17},
	{0x16,0x17,0x18},
	{0x17,0x18,0x19},

	{0x21,0x22,0x23},
	{0x22,0x23,0x24},
	{0x23,0x24,0x25},
	{0x24,0x25,0x26},
	{0x25,0x26,0x27},
	{0x26,0x27,0x28},
	{0x27,0x28,0x29},
	// 刻子
	{0x01,0x01,0x01},
	{0x02,0x02,0x02},
	{0x03,0x03,0x03},
	{0x04,0x04,0x04},
	{0x05,0x05,0x05},
	{0x06,0x06,0x06},
	{0x07,0x07,0x07},
	{0x08,0x08,0x08},
	{0x09,0x09,0x09},

	{0x11,0x11,0x11},
	{0x12,0x12,0x12},
	{0x13,0x13,0x13},
	{0x14,0x14,0x14},
	{0x15,0x15,0x15},
	{0x16,0x16,0x16},
	{0x17,0x17,0x17},
	{0x18,0x18,0x18},
	{0x19,0x19,0x19},

	{0x21,0x21,0x21},
	{0x22,0x22,0x22},
	{0x23,0x23,0x23},
	{0x24,0x24,0x24},
	{0x25,0x25,0x25},
	{0x26,0x26,0x26},
	{0x27,0x27,0x27},
	{0x28,0x28,0x28},
	{0x29,0x29,0x29},
	// 对子(将)
	{0x01,0x01,0x00},
	{0x02,0x02,0x00},
	{0x03,0x03,0x00},
	{0x04,0x04,0x00},
	{0x05,0x05,0x00},
	{0x06,0x06,0x00},
	{0x07,0x07,0x00},
	{0x08,0x08,0x00},
	{0x09,0x09,0x00},

	{0x11,0x11,0x00},
	{0x12,0x12,0x00},
	{0x13,0x13,0x00},
	{0x14,0x14,0x00},
	{0x15,0x15,0x00},
	{0x16,0x16,0x00},
	{0x17,0x17,0x00},
	{0x18,0x18,0x00},
	{0x19,0x19,0x00},

	{0x21,0x21,0x00},
	{0x22,0x22,0x00},
	{0x23,0x23,0x00},
	{0x24,0x24,0x00},
	{0x25,0x25,0x00},
	{0x26,0x26,0x00},
	{0x27,0x27,0x00},
	{0x28,0x28,0x00},
	{0x29,0x29,0x00},
};

char PairStart() {
    return BLOCK_PPZ_START;
}
char PairEnd(){
    return BLOCK_PPZ_START + BLOCK_PPZ_COUNT;
}

char BlockStart() {
    return BLOCK_ABC_START;
}
char BlockEnd(){
    return BLOCK_ABC_START + BLOCK_ABC_COUNT + BLOCK_TTT_COUNT;
}

typedef long long indice; // 手牌

set<indice> huSet;
bool ValidIndice(indice d);

// 选牌
void Hu(){
    // PPZ
    indice d;
	for (long long i = PairStart(); i < PairEnd(); i++) {
        d = i;
		huSet.insert(d);
	}
    // Block+PPZ	
    unsigned char* pc=(unsigned char*)&d;
    for (long long i = PairStart(); i < PairEnd(); i++) {
        pc[0] = i;
        for (long long j = BlockStart(); j < BlockEnd(); j ++) {		    
            pc[0] = i; pc[1] = j;
            if (ValidIndice(d)){
                huSet.insert(d);                
            }
            d = 0;
			
		}
    }
    for (long long i = PairStart(); i < PairEnd(); i++) {
        pc[0] = i; 
        for (long long j = BlockStart(); j < BlockEnd(); j ++) {		    
            pc[0] = i; pc[1] = j;
            if (!ValidIndice(d)) continue;
            for (long long k = BlockStart(); k < BlockEnd(); k ++) {		    
                pc[0] = i; pc[1] = j; pc[2] = k;
                if (ValidIndice(d)){
                    // 排序，加入去重
                    for (int start = 0; start < 2; start++)
                    for (int end = 2; end >= 1 + start; end--)
                    {
                        if (pc[end] < pc[end-1]){
                            pc[end] ^= pc[end-1];
                            pc[end-1] ^= pc[end];
                            pc[end] ^= pc[end-1];
                        }
                    }                    
                    huSet.insert(d);                    
                }
                d = 0;
            }			
		}
    }
    for (long long i = PairStart(); i < PairEnd(); i++) {
        pc[0] = i; 
        for (long long j = BlockStart(); j < BlockEnd(); j ++) {		    
            pc[0] = i; pc[1] = j; 
            if (!ValidIndice(d)) continue;
            for (long long k = BlockStart(); k < BlockEnd(); k ++) {		    
                pc[0] = i; pc[1] = j; pc[2] = k;
                if (!ValidIndice(d)) continue;
                for (long long m = BlockStart(); m < BlockEnd(); m ++) {		    
                    pc[0] = i; pc[1] = j; pc[2] = k; pc[3] = m;
                    if (ValidIndice(d)){
                        // 排序，加入去重
                        for (int start = 0; start < 3; start++)
                        for (int end = 3; end >= 1 + start; end--)
                        {
                            if (pc[end] < pc[end-1]){
                                pc[end] ^= pc[end-1];
                                pc[end-1] ^= pc[end];
                                pc[end] ^= pc[end-1];
                            }
                        }

                        huSet.insert(d);                        
                    }
                    d = 0;
                }
            }			
		}
    }    
    
    for (long long i = PairStart(); i < PairEnd(); i++) {
        pc[0] = i;
        for (long long j = BlockStart(); j < BlockEnd(); j ++) {		    
            pc[0] = i; pc[1] = j; 
            if (!ValidIndice(d)) continue;
            for (long long k = BlockStart(); k < BlockEnd(); k ++) {		    
                pc[0] = i; pc[1] = j; pc[2] = k; 
                if (!ValidIndice(d)) continue;
                for (long long m = BlockStart(); m < BlockEnd(); m ++) {		    
                    pc[0] = i; pc[1] = j; pc[2] = k; pc[3] = m;
                    if (!ValidIndice(d)) continue;
                    for (long long n = BlockStart(); n < BlockEnd(); n ++) {		    
                        pc[0] = i; pc[1] = j; pc[2] = k; pc[3] = m; pc[4] = n;
                        if (ValidIndice(d)){
                            // 排序，加入去重
                            for (int start = 0; start < 4; start++)
                            for (int end = 4; end >= 1 + start; end--)
                            {
                                if (pc[end] < pc[end-1]){
                                    pc[end] ^= pc[end-1];
                                    pc[end-1] ^= pc[end];
                                    pc[end] ^= pc[end-1];
                                }
                            }

                            huSet.insert(d);                            
                        }
                        d = 0;
                    }
                }
            }			
		}
    }    
}

bool ValidIndice(indice d){
    static char have[48];
    memset(have, 0, sizeof(have));
    while (d > 0){
        int t = d & 0xff;
        char* p = TileBlock[t];
        for (int i = 0; i < 3; i++){
            if (p[i] > 0){
                have[p[i]] ++;
                if (have[p[i]] > 4){
                    // 最多只有4张牌
                    return false;
                } 
            }
        }
        d = d >> 8;
    }
    return true;
}



bool ExportHuComb(indice d, char pc[17]);
int main(){
	Hu();
	// 导出数据
	ofstream huComb("huComb.bin", ios::trunc | ios::binary);
	if (huComb.is_open())
	{
		for (set<indice>::iterator it = huSet.begin(); it != huSet.end(); it++) {
			char hexStr[17] = {};
			ExportHuComb(*it, hexStr);
			huComb << hexStr << endl;			
		}
		huComb.close();		
	}

	return 0;
} 
  

bool ExportHuComb(indice d, char pc[17]) {
	
	// 至多14张牌 
    // 两张0 作间隔
    // 编码(万)：0x01~0x09 
    // 编码(筒)：0x11~0x19 
    // 编码(条)：0x21~0x29 
	char tilew[10] = {};  
    char tilep[10] = {};  
    char tilet[10] = {};  
    while (d > 0){
        char* p = TileBlock[d & 0xff];
        for (int i = 0; i < 3; i++){
            if (p[i] <= 0 ) continue;

            if (p[i] < 10){ // 万
                tilew[p[i]] ++;                
            }else if (p[i] > 32){ // 条  32 = 0x20
                tilet[p[i] - 32] ++;        
            }else{
                tilep[p[i] - 16] ++;   // 筒 16 = 0x10
            }
        }
        d = d >> 8;
    }
    int k = 0;
    for (int i=1; i <10; i++){
        while (tilew[i]> 0){
            pc[k++] = i + 48;
            tilew[i] = tilew[i] - 1;
        }
    }
    if (k > 0) pc[k++] = 48; // 前缀 优化
    for (int i=1; i <10; i++){
        while (tilep[i]> 0){
            pc[k++] = i + 48;
            tilep[i] = tilep[i] - 1;
        }
    }
    if (k > 0) pc[k++] = 48; // 前缀 优化
    for (int i=1; i <10; i++){
        while (tilet[i]> 0){
            pc[k++] = i + 48;
            tilet[i] = tilet[i] - 1;
        }
    }
    pc[k++] = 0;

	return  true;
}
